#include <algorithm>
#include <iostream>

#ifdef _MSC_VER
#include "msvc_io.h"
#else
#include "posix_io.h"
#endif

#include "dedup.h"
#include "io_exceptions.h"


dedup::dedup(std::string &path) : total_size(0), dedup_size(0), abs_path(path)
{
    time(&start_time);
}


dedup::~dedup() { }


void dedup::run()
{
    recurs_dir(abs_path, nodes, total_size);
    sort();
    dedup_files();
}


void dedup::sort()
{
    std::sort(nodes.begin(), nodes.end());
}


void dedup::dedup_files()
{
    if (nodes.empty()) {
        return;
    }
    std::vector<filenode> cmp;
    cmp.push_back(nodes[0]);

    for (std::vector<filenode>::iterator it = nodes.begin() + 1; it != nodes.end(); it++) {
        if (it->get_size() == (it - 1)->get_size()) {
            cmp.push_back(*it);
        } else {
            duplicate(cmp);
            cmp.clear();
            cmp.push_back(*it);
        }
    }

    if (!cmp.empty()) {
        duplicate(cmp);
        cmp.clear();
    }
}


void dedup::duplicate(std::vector<filenode> &cmp)
{
    if (cmp.size() < 2)
        return;

    std::vector<hash_t> hashes;

    for (std::vector<filenode>::iterator iter = cmp.begin(); iter != cmp.end(); iter++) {
        hashes.push_back(iter->get_hash());
    }

    std::sort(hashes.begin(), hashes.end());

    size_t count_duplicate_files = 0;

    hash_t prev = *(hashes.begin());

    for (size_t i = 1; i < hashes.size(); i++) {
        if (hashes[i] == prev) {
            count_duplicate_files++;
        } else {
            prev = hashes[i];
        }
    }

    dedup_size += count_duplicate_files * cmp[0].get_size();
}


long long int dedup::get_total_size() const
{
    return total_size;
}


long long int dedup::get_dedup_size() const
{
    return dedup_size;
}


float dedup::get_processing_speed() const
{
    time_t end_time;
    time(&end_time);
    int time = end_time - start_time == 0 ? 1 : end_time - start_time;
    float speed = total_size / 1000000.0 / time;
    return speed;
}


long long int dedup::get_count_files() const
{
    return nodes.size();
}
